import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.tdb.TDBFactory;




import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.Writer;
import java.lang.reflect.Array;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.sql.SQLException;


import com.hp.hpl.jena.*;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ReadWrite;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFactory;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Literal;

import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.sparql.resultset.ResultSetMem;
import com.hp.hpl.jena.sparql.resultset.ResultSetRewindable;

import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.util.FileUtils;

import au.com.bytecode.opencsv.*;


/**
 * 
 */

/**
 * @author Paola
 *
 *This class: 
 *-create and load the dump in a model 
 *-create all the queries to be executed on the tdb 
 *-execute all the queries and save the results in appropriate execution structures
 *-print the results contained in the execution structures in the different output files 
 *-close all the model, queries, tdb etc...
 *
 *
 */
public class RES {
	
	private Dataset dataset;
	
	private Model tdb;
	
	private String source="";
	private String directory=""; 
	
	


	
	
  public  void configJob(InfoJobThesaurus job)
	          throws Exception
	{

try{
		source = job.getPathdumpResource().trim()+job.getNameResource().trim();
		//System.out.println("source total "+source);	
		directory =job.getPathtdbResource().trim();
					
		
		dataset = TDBFactory.createDataset(directory) ;
		tdb = dataset.getDefaultModel();
}catch (Exception e) {
			throw new Exception("configJob:  problemi tdb! nome risorsa: \n" +job.getPathdumpResource()+job.getNameResource()+
					" " +job.getPathtdbResource());
	    	}	
		
	
	}
	
	//esegue le query
  public  void executeJob(InfoJobThesaurus job)
          throws Exception
{
	  if(job instanceof InfoJobThesaurus)
	  {
		  //altri tipi di valutazione
	  }

	  if(job instanceof InfoJobThesaurusME)
	  {
		  executeMultiligualEvaluation((InfoJobThesaurusME)job);
	  }
	  
}
  
  
  
  
  
  public  void closeJob(InfoJobThesaurus job)
          throws Exception
{
	  
	  //org.apache.commons.io.FileUtils.cleanDirectory(new File( "C:\\Users\\Paola\\workspace\\multilingualThesauri\\tdb"));
	  
	  //File f=new File( "C:\\Users\\Paola\\workspace\\multilingualThesauri\\tdb");
	  /*
	  for(File file: f.listFiles()) 
	  {
		  if (!file.getName().equalsIgnoreCase("SPOG.idn"))
		  {
			  
			  if (!file.exists()) System.out.println("Delete: no such file or directory: "+file.getName());
			 
			  if (!file.canWrite()) System.out.println("Delete: write protected: ");
			  // If it is a directory, make sure it is empty
			  boolean success = file.delete();
			  // And throw an exception if it didn't work for some (unknown) reason.
			  // For example, because of a bug with Java 1.1.1 on Linux, 
			  // directory deletion always fails 
			  if (!success) System.out.println("Delete: deletion failed");	 
			    
		  }

	  }
	  */
	  
	  
	 // Path path = FileSystems.getDefault().getPath("C:\\Users\\Paola\\workspace\\multilingualThesauri\\tdb\\", "GOSP.dat");
	 // Files.delete(path);
	  
  	//System.runFinalization();
  	//System.gc();		  

	  

	  
	  
}  
	
  
  
  
	//esegue le query
	  private  void executeMultiligualEvaluation(InfoJobThesaurusME job)
	          throws Exception
	{
	 
	   //strutture query
	   HashMap<String, String> querylist=new HashMap<String, String>();
	    String query="";
	    
	    //strutture risultati query 
	    ResultSet results=null;
	    ResultSetMem r= new ResultSetMem();
	    
	    	
		//struttura risultati queries
		HashMap<String,ResultSetRewindable> restot = new HashMap<String,ResultSetRewindable>();
	    
	    //stampa risultati su File 
	    PrintToFileStatistics ptf= new PrintToFileStatistics();
	    
		//struttura per i dati globali thesauro <nomethes,lang-%concepts>
		//struttura per dati singolo thesauro
	    HashMap<String,String> hashfr=new HashMap<String,String>();
		ConceptsForLanguage prefLabel = new ConceptsForLanguage();
		ConceptsForLanguage altLabel = new ConceptsForLanguage();
		ConceptsForLanguage definition = new ConceptsForLanguage();
	    
	    
		   //file per percentuali totali
	  	//creo nome files risultati totali
		String[] labeline;
		
		    StringBuilder nameaux= new StringBuilder();
		    
		    nameaux.append(job.getPathfileres());
		    nameaux.append("TotalEvaluation");
		   
		    	    
	    
	    
	    
	    
	    labeline = new String[] {"_prefLable.csv"};
	    FileWriter outFilepl = new FileWriter(nameaux.toString()+labeline[0].toString().trim(), Boolean.TRUE);
	    System.out.println("nome pref: "+nameaux.toString()+labeline[0].toString().trim());
	    labeline = new String[] {"_altLable.csv"};
	    FileWriter outFileal = new FileWriter(nameaux.toString().trim()+labeline[0].toString().trim(), Boolean.TRUE);
	    System.out.println("nome alt: "+nameaux.toString()+labeline[0].toString().trim());	    
	    labeline = new String[] {"_definition.csv"};
	    FileWriter outFiledef = new FileWriter(nameaux.toString().trim()+labeline[0].toString().trim(), Boolean.TRUE);
	    System.out.println("nome def: "+nameaux.toString()+labeline[0].toString().trim());
	    CSVWriter csvfal= new CSVWriter(outFileal);
	    CSVWriter csvfpl= new CSVWriter(outFilepl);
	    CSVWriter csvfdef= new CSVWriter(outFiledef);
    	//scrivi intestazione file percentuali totali
	    ArrayList<String[]> allines= new ArrayList<String[]>();
	    allines.add(prefLabel.keyToStringArray());
	    for(String[] l: allines)
	    {
	    	csvfal.writeNext(l);
	    	csvfpl.writeNext(l);
	    	csvfdef.writeNext(l);
	    }
	    

	    
   
	    ///crea query
	    querylist=createQueryList(job);
	    ListIterator<String> qlit;
	    QueryExecution qexec=null;
	    
	    dataset.begin(ReadWrite.READ);

	    try{
	    
		  InputStream in = FileManager.get().open( source );
		  if (in == null) {
			  throw new IllegalArgumentException("File: " + source + " not found");
			}
		  if (job.getFormatResource().equalsIgnoreCase("RDF"))
		  {
			  tdb.read(in, null, "RDF/XML");
		  }
		  else{
			  if (job.getFormatResource().equalsIgnoreCase("nt"))
			  {
				  tdb.read(in, null, "N-TRIPLE");
			  }
			  else{
				  if (job.getFormatResource().equalsIgnoreCase("ttl"))
				  {
					  tdb.read(in, null, "TURTLE");
				  }
				  else{
					  if (job.getFormatResource().equalsIgnoreCase("n3"))
					  {
						  tdb.read(in, null, "N3");
					  }
					  else
					  {
						  throw new IllegalArgumentException("Wrong thesaurus File Extension");
					  }

				  }
				  
			  }
		  }	    
	    
	    
	    
		    
		  try{
	  
	  //iterating over values only
	  for (Map.Entry<String, String> entry : querylist.entrySet()) {
       
		  
		  System.out.println("Start query execution \n");
		  System.out.println(entry.getValue().trim() +"\n");
		  
		  qexec = QueryExecutionFactory.create(entry.getValue().trim(), tdb) ;
	    	results = qexec.execSelect();
	    	//ResultSetFormatter.out(results);
	    	/*
	    	if (results.getRowNumber()==0)
	    	{
	    		throw new Exception("executeMultiligualEvaluation: risultato query vuoto");
	    	}*/
	    	System.out.println("\nEnd query execution");
	    	
	    	restot.put(entry.getKey().trim(), ResultSetFactory.makeRewindable(results));
	    	

        }
	    
	   

	    computeStatisticsResults(restot,prefLabel,altLabel,definition,hashfr);
    	System.out.println("Computation results finished\n");
    	
	 
    	
	    //calcolo e stampa percentuali nei file 
    	printMultiligualEvaluationResults(job,prefLabel,altLabel,definition,hashfr, csvfpl, csvfal, csvfdef);
    	
    	//chiudi file
    	csvfal.close();
    	csvfpl.close();
    	csvfdef.close();
    	outFilepl.close();
    	outFileal.close();
    	outFiledef.close();	
    	System.out.println("Results print finished\n");

    	
	    }
	   finally {qexec.close(); }
	 } finally { tdb.close(); dataset.end(); dataset.close();}
	    
	    
	    
	    
	    
	}
	  
	  
	  
	  
	  private HashMap<String, String> createQueryList(InfoJobThesaurus job)
	  { 
		  //lista di query con questi campi es: "altLabel" + "queryaltLabel"
		  HashMap<String, String> ql=new HashMap<String, String>();
		  String querypreflabel="";
		  
		  
		  for(String p: job.getPropertytypes())
		  {
			  querypreflabel="";
			  if (p.equalsIgnoreCase("prefLabel"))
			  {
					querypreflabel="select  ?l (COUNT(?term) AS ?nterm )"+  
							"where { " +
							 "?term a <http://www.w3.org/2004/02/skos/core#Concept>."+
							"?term <http://www.w3.org/2008/05/skos-xl#prefLabel> ?ulabel . " +
							"?ulabel <http://www.w3.org/2008/05/skos-xl#literalForm> ?label."+
							"FILTER (regex(str(?term), '" +  job.getURIspaceResource().trim()  + "'))} " +
							"GROUP BY (lang(?label) AS ?l)";
			


			  }
			  if (p.equalsIgnoreCase("altLabel"))
			  {			querypreflabel= "select  ?l (COUNT(?term) AS ?nterm ) \n"+  
						"where { " +
						 "?term a <http://www.w3.org/2004/02/skos/core#Concept> ."+
						"?term <http://www.w3.org/2004/02/skos/core#altLabel> ?label\n " +
						"FILTER (regex(str(?term), '" +  job.getURIspaceResource().trim()  + "'))} " +
						"GROUP BY (lang(?label) AS ?l)";


			  }
			  if(p.equalsIgnoreCase("definition"))
			  {
					querypreflabel= "select  ?l (COUNT(?term) AS ?nterm ) \n"+  
							"where { " +
							 "?term a <http://www.w3.org/2004/02/skos/core#Concept> ."+
							"?term <http://www.w3.org/2004/02/skos/core#definition> ?label.\n " +
							"FILTER (regex(str(?term), '" +  job.getURIspaceResource().trim()  + "'))} " +
							"GROUP BY (lang(?label) AS ?l)";

			  }
			  

				ql.put(p, querypreflabel);
		  }
	  
		  //query statistiche totali 
			querypreflabel= "select  (COUNT(?term) AS ?nterm )\n"+  
	  				"where { " +
	  				 "?term a <http://www.w3.org/2004/02/skos/core#Concept>." +
	  				 "FILTER (regex(str(?term), '" +  job.getURIspaceResource().trim()  + "'))}";
			
;
			
			ql.put("prefLabel", querypreflabel);
			System.out.print(querypreflabel+"\n");
			
		//System.out.print(querypreflabel+"\n");
		return ql;
	  }
	
	  private  void printMultiligualEvaluationResults(InfoJobThesaurusME job, ConceptsForLanguage pl, ConceptsForLanguage al, 
			  ConceptsForLanguage def, HashMap<String,String> rt, CSVWriter csvfpl,CSVWriter csvfal,CSVWriter csvfdef )
	          throws Exception
	{
 
		  
		    
		    //stampa risultati nel file del thesauro
		  PrintToFileStatistics.printThesaurusMultilingualResults(job, pl, al, def, rt);
		    
		    //stampa risultati nei file comuni
		  PrintToFileStatistics.printTotalMultilingualResults(job, pl, al, def, rt, csvfpl, csvfal,csvfdef);
		   
		    

	}
	
	  
	  
	  private  void computeStatisticsResults(HashMap<String,ResultSetRewindable> results, ConceptsForLanguage pl, ConceptsForLanguage al, 
			  ConceptsForLanguage def, HashMap<String,String> rt)
	          throws Exception
	{
		  
		  String stsoln2="";
		  ResultSet r;
		  Double totalconcepts=0.0;
		  String tc="";
		  String l="";
		  QuerySolution q=null;
		  Integer perc=0;
		  Integer conc4lang=0;
		  String[] aux= new String[2];
		  
		  //System.out.print("dimensione risutato "+results.size() +"\n");
		  
		  for (Map.Entry<String, ResultSetRewindable> entry : results.entrySet()){
			  
			  entry.getValue().reset();
			  
			  //System.out.print("dimensione risutato totalconcepts:"+ entry.getValue());
			  
			  
			  if (entry.getKey().equalsIgnoreCase("totalnumberconcepts"))
			  {
				  r= entry.getValue();
				  System.out.print("dimensione risutato totalnumberconcepts:\n");
				 ResultSetFormatter.out(r);
				  totalconcepts=r.next().getLiteral("?nterm").getDouble();
				  rt.put("totalnumberconcepts", String.valueOf(totalconcepts));
				  //totalconcepts=Double.valueOf(aux[0]);
					
			  }
			  
		  }

		  
		  
		  
		  for (Map.Entry<String, ResultSetRewindable> entry : results.entrySet()){
			  entry.getValue().reset();
			  r= entry.getValue();
			  
		  //riempie le strutture per le statistiche globali 
			  if (entry.getKey().equalsIgnoreCase("prefLabel"))
			  {
				  System.out.print("dimensione risultato prelabel:\n");
				  ResultSetFormatter.out(r);
					while (r.hasNext())
				    {
						q=r.next();
						conc4lang=q.getLiteral("?nterm").getInt();
						if(conc4lang!=0)
						{
						l=q.getLiteral("?l").toString();
						
						pl.setNumberConceptsforLanguage(l,conc4lang);
						}
				    }
			  }

			  if (entry.getKey().equalsIgnoreCase("altLabel"))
			  {
				  System.out.print("dimensione risultato altlabel\n");
				  ResultSetFormatter.out(r);
					while (r.hasNext())
				    {
						q=r.next();
						conc4lang=q.getLiteral("?nterm").getInt();
						
						if(conc4lang!=0)
						{
						l=q.getLiteral("?l").toString();
						
						
						//perc=(int) ((100*conc4lang)/totalconcepts);
						al.setNumberConceptsforLanguage(l,conc4lang);
						}
				    }

			  }
			  if (entry.getKey().equalsIgnoreCase("definition"))
			  {
				  
				  System.out.print("dimensione risultato definition\n");
				  ResultSetFormatter.out(r);
					while (r.hasNext())
				    {
						q=r.next();
						conc4lang=q.getLiteral("?nterm").getInt();
						if(conc4lang!=0)
						{
							l=q.getLiteral("?l").toString();
						def.setNumberConceptsforLanguage(l,conc4lang);
						}
				    }
				  
			  }
			  //riempie le strutture per statistiche singole
		  }
	}
}


